Skip to content

Z06-04 专题-Cloudflare

[TOC]

基础概念

本章将深入解析 Cloudflare 开发生态的两大基石——Workers 与 Pages,并探讨边缘计算架构与传统云服务的核心区别。

Cloudflare Workers:边缘计算引擎

什么是 Workers

Cloudflare Workers 是一个边缘计算无服务器平台(Edge Computing Serverless Platform)。 与传统云服务不同,它允许开发者编写代码(JavaScript, TypeScript, Rust 等),并将这些代码部署到 Cloudflare 遍布全球 300 多个城市的服务器节点上。

  • 运行机制: 当用户访问应用时,代码会在离用户物理距离最近的节点上运行,而不是在遥远的源服务器上运行。
  • 核心优势: 这种架构消除了网络延迟,让应用获得物理极限级别的访问速度。

核心技术:V8 Isolates vs 容器

Workers 极速响应的秘密在于其底层技术架构。它不使用 AWS Lambda 等传统 Serverless 平台常见的容器(Container)或虚拟机,而是采用谷歌 Chrome 浏览器的 V8 Isolates 引擎技术。

技术架构对比:

特性传统 Serverless (如 AWS Lambda)Cloudflare Workers
底层技术容器 / 微型操作系统V8 Isolates (轻量级上下文)
启动机制需启动操作系统环境在现有进程中创建上下文
形象比喻专门启动一辆卡车来送一个披萨(启动慢、开销大)在同一辆已经发动的卡车上多放一个披萨盒(零启动时间)
冷启动时间数百毫秒甚至几秒0ms 冷启动 (几毫秒内执行)

Workers 的核心能力

Workers 处于用户和源服务器之间,可以胜任多种角色:

  1. Backendless (无后端): 配合 D1 (数据库)、KV (键值存储)、R2 (对象存储),构建完全运行在边缘的全栈应用,无需任何传统 Linux 服务器。
  2. 中间件/代理 (Middleware/Proxy): 修改请求/响应头(Auth Header)、重定向路由、进行 A/B 测试。
  3. 性能优化: 自定义缓存逻辑或根据设备动态调整图片尺寸。

代码示例

Workers 基于 Web 标准 Service Worker API 构建,开发者使用的是熟悉的 Fetch, Request, Response 对象。

一个最简单的拦截请求并返回 "Hello World" 的 Worker 如下:

javascript
export default {
  async fetch(request, env, ctx) {
    return new Response('Hello World')
  }
}

(注:基于笔记描述补充的标准 Hello World 示例)


Cloudflare Pages:全栈托管平台

什么是 Pages

如果说 Workers 是为了解决“后端逻辑”在边缘运行的问题,那么 Cloudflare Pages 就是为了解决“前端页面”在边缘托管和构建的问题。它主要对标 Vercel 和 Netlify,是托管 Vue、React 等前端项目的最佳方案。

核心工作流:自动化构建

Pages 改变了传统“本地打包 -> 手动上传 -> 配置 Nginx”的繁琐流程,实现了现代化的 GitOps 工作流:

  1. Git 集成: 连接 GitHub/GitLab 仓库。
  2. 自动构建: 云端监听到代码提交后,自动运行 npm installnpm build
  3. 全球分发: 构建生成的静态文件(HTML/CSS/JS)自动分发到全球 300+ 节点。
  4. 预览环境 (Preview Deployments): 每个 Pull Request 都会自动部署一个临时的、独立的 URL(如 pr-123.project.pages.dev)供团队测试,合并后才会更新主环境。

Pages 与 Workers 的区别

  • Workers:代码优先。 适合写 API、代理、复杂逻辑。虽然能返回 HTML,但不适合管理大量静态资源。
  • Pages:文件/资产优先。 专为托管静态网站设计,擅长处理文件存储和分发。

Pages Functions (全栈能力)

这是 Pages 的“杀手锏”。通过在项目根目录创建 functions 文件夹,开发者可以在 Pages 项目中直接编写后端逻辑。

  • 自动路由: functions 目录下的文件会自动部署为 Workers 并生成 API 路由。

    • functions/api/login.js -> 自动映射为 /api/login 接口。
  • Monorepo 优势: 前端(Vue)与后端(Functions)在同一个仓库中管理,共享环境变量和 D1/KV 绑定,无需跨域配置(因为同属一个域名)。


架构选型建议

在迁移传统应用(如阿里云上的 Vue + Nginx)时,有两种架构模式可供选择:

架构 A:混合模式

  • 前端: 托管在 Cloudflare Pages。
  • 后端: 独立的 Cloudflare Workers 项目。
  • 连接: 前端通过 HTTP 请求调用后端 URL。
  • 特点: 前后端完全解耦,适合独立开发团队。

架构 B:全栈 Pages 模式 (推荐)

  • 结构: 单个 GitHub 仓库 (Monorepo)。
  • 前端: Vue/React 代码。
  • 后端: functions/ 目录下的 API 代码。
  • 特点: 管理方便,共享资源绑定,无需维护两个项目,适合个人开发者和全栈应用。

核心计算

本章将深入剖析 Cloudflare 的计算运行时环境,从底层的 V8 隔离技术到上层的 Pages Functions 开发模式,帮助开发者理解为何它能实现“零冷启动”以及如何构建高效的全栈应用。

V8 引擎机制

Cloudflare Workers 的核心竞争力在于其独特的运行机制,这与 AWS Lambda 等传统 Serverless 方案有着本质区别。

V8 Isolates 技术原理

Workers 并不使用容器 (Container)虚拟机,而是采用了谷歌 Chrome 浏览器的 V8 Isolates 引擎技术。

  • 传统 Serverless (如 AWS Lambda):

  • 机制: 当请求到达时,云服务商需要启动一个微型操作系统环境(容器)。

  • 代价: 这个过程会产生显著的**“冷启动”**时间,通常需要数百毫秒甚至几秒。

  • Cloudflare Workers:

  • 机制: 它不启动新的操作系统,而是在现有的进程中创建一个轻量级的“上下文”(Isolate)。

  • 优势: 实现了 0ms 冷启动,代码可以在几毫秒内开始执行。

形象比喻:披萨卡车

为了更好地理解这两种架构的区别,我们可以使用“披萨卡车”的比喻:

  • 传统 Serverless: 就像为了送一个披萨,专门启动了一辆卡车。启动引擎很慢,且每送一单都要消耗整辆车的资源(开销大)。
  • Workers: 就像在同一辆已经发动的卡车上多放了一个披萨盒。卡车本身已经在运行,放入披萨盒几乎不需要时间(零启动时间,开销极小)。

Pages 函数 (Pages Functions)

Cloudflare Pages 不仅支持静态文件托管,还通过 Pages Functions 提供了完整的后端能力,使其成为全栈开发的利器。

目录即路由

Pages 遵循“约定优于配置”的原则。在项目根目录下的 functions 文件夹里的代码,会自动部署为后端 API。

  • 文件映射规则:

  • functions/api/login.js -> 自动映射为 /api/login 接口。

  • functions/api/user.js -> 自动映射为 /api/user 接口。

  • 核心优势: 前端(Vue/React)和后端(Workers)代码放在同一个仓库里,Cloudflare 自动处理路由和构建,无需复杂的跨域配置。

实战代码:115 网盘通用接口

以下是一个真实的 Pages Function 示例,用于中转请求并欺骗 115 服务器。

文件路径: functions/api/115.js

javascript
export async function onRequest(context) {
  // 从环境变量中获取 Cookie
  const COOKIE = context.env.COOKIE_115

  if (!COOKIE) {
    return new Response(JSON.stringify({ state: false, error: '未配置 Cookie' }), {
      headers: { 'Content-Type': 'application/json' }
    })
  }

  // 获取前端传来的参数 (URL)
  const url = new URL(context.request.url)
  const targetUrl = url.searchParams.get('url') // 例如 ?url=https://webapi.115.com/...

  if (!targetUrl) {
    return new Response('Missing url param', { status: 400 })
  }

  // 发起请求给 115
  // 注意:这里伪造了 User-Agent 和 Cookie
  const resp = await fetch(targetUrl, {
    headers: {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',
      Cookie: COOKIE
    }
  })

  // 把 115 的返回结果直接透传给前端
  const data = await resp.json()
  return new Response(JSON.stringify(data), {
    headers: { 'Content-Type': 'application/json' }
  })
}

API 解析:

  • onRequest(context): Pages Functions 的入口处理函数。
  • context.env: 用于访问环境变量(如 COOKIE_115)和绑定的资源(如 D1, KV)。
  • context.request: 标准的 Web Request 对象,包含 URL、Headers 等信息。

实战代码:图片代理服务

针对 115 图片防盗链的处理,我们可以编写一个专门的图片代理 Function。

文件路径: functions/api/img-proxy.js

javascript
export async function onRequest(context) {
  const COOKIE = context.env.COOKIE_115
  const url = new URL(context.request.url)
  const targetUrl = url.searchParams.get('url')

  if (!targetUrl) return new Response('Missing URL', { status: 400 })

  // 请求图片,带上 Cookie 和 Referer
  const resp = await fetch(targetUrl, {
    headers: {
      Cookie: COOKIE,
      Referer: 'https://115.com/' // 关键:骗过防盗链
    }
  })

  // 直接返回图片流,不要 await resp.blob(),以节省内存
  return new Response(resp.body, {
    headers: {
      'Content-Type': resp.headers.get('Content-Type') || 'image/jpeg'
    }
  })
}

全栈开发模式

Cloudflare Pages 提供了两种主要的开发架构模式,开发者应根据项目需求进行选择。

架构对比

架构模式描述适用场景
架构 A:混合模式前端在 Pages,后端是独立的 Workers 项目。前后端完全解耦,通过 HTTP 调用。适合独立开发团队,或者后端逻辑极度复杂需要独立管理的场景。
架构 B:全栈 Pages 模式 (推荐)Monorepo 结构。前端代码和 functions/ 目录下的 API 代码在同一个仓库。管理方便,共享环境变量和 D1/KV 绑定,无需跨域配置。非常适合个人开发者构建全栈应用。

本地全栈开发环境配置

为了在本地模拟 Cloudflare 环境(同时运行 Vue 前端和 Functions 后端),我们需要利用 Wrangler 进行代理。

1. 配置本地环境变量 在项目根目录创建 .dev.vars 文件(注意:此文件不应提交到 Git):

text
COOKIE_115=UID=12345;CID=abcde;SEID=...

2. 修改启动脚本 修改 package.jsonscripts 字段,使用 Wrangler 来启动开发服务器:

json
"scripts": {
  "dev": "vite",
  "build": "vite build",
  "preview": "vite preview",
  "pages:dev": "wrangler pages dev -- proxy 5173"
}

3. 启动命令 运行 npm run pages:dev

运行原理解析:

  1. Wrangler 启动并自动运行 npm run dev (Vite 服务器)。
  2. Wrangler 建立一个代理服务器(通常在 http://localhost:8788)。
  3. 请求拦截:
  • 页面请求 /api/115 -> Wrangler 拦截 -> 执行 functions/api/115.js(读取 .dev.vars 中的变量)。
  • 页面请求静态资源 -> Wrangler 转发给 Vite (端口 5173)。

通过这种方式,你可以在本地完整模拟线上的全栈运行环境,无需部署即可调试后端 API 和数据库逻辑。

数据存储

本章将详细介绍 Cloudflare 的三大核心存储解决方案:D1 (SQL 数据库)KV (键值存储)R2 (对象存储)。我们将从核心概念、适用场景、定价模式以及详细的 API 操作指南四个维度进行深入解析。


D1 数据库

什么是 D1

Cloudflare D1 是 Cloudflare 推出的原生无服务器(Serverless)关系型数据库。 简单来说,它是一个构建在 Cloudflare 全球网络边缘(Edge)上的 SQLite 数据库。

它的设计目标是为 Workers 应用提供一个低延迟、零配置、且支持标准 SQL 的数据存储方案。

核心特性

  1. 基于 SQLite: 并非 MySQL 或 PostgreSQL。这意味着你可以使用熟悉的 SQL 语法,且启动速度极快。
  2. 原生无服务器 (Serverless): 无需配置服务器或管理集群。通过 CLI 或控制台即可瞬间创建。
  3. 全球分布 (Global Distribution):
  • 读操作: 支持全球读复制,自动在靠近用户的位置创建只读副本,实现极低延迟。
  • 写操作: 发送到主实例(Primary),然后异步同步到其他副本。
  1. 深度集成: 通过绑定(Binding)机制,Worker 代码可以直接调用 D1,无需处理连接池或鉴权。

局限性与注意事项

  • 单库容量限制: 目前单个数据库限制为 10 GB
  • 并发写入性能: 由于 SQLite 特性,单主节点模式在处理极高并发写入时性能不如传统数据库。
  • 事务支持: 支持事务,但受限于分布式环境,复杂事务处理能力有限。

适用场景

  • 边缘应用: 电商产品目录、内容管理系统。
  • SaaS 多租户架构: 适合“一个租户一个数据库”的隔离模式。
  • 高读低写: 针对“读多写少”场景优化。

定价模式

D1 不按实例时间计费,而是基于存储量读写行数

  • 免费版: 每天 500 万行读取,10 万行写入,5 GB 存储。
  • 付费版: 读取 $0.001/百万行,写入 $1.00/百万行,存储 $0.75/GB/月。

D1 常用接口

D1 的 API 设计遵循 Prepare -> Bind -> Execute 的链式调用模式,主要围绕 env.DB 对象进行操作。

核心流程方法

prepare(sql)
  • 作用: 所有操作的起点。传入 SQL 字符串,返回一个 PreparedStatement 对象。此时 SQL 并未执行,只是被编译/准备好了。
bind(param1, param2, ...)
  • 作用: 将变量安全地填充到 SQL 语句的占位符 (?) 中。
  • 安全警告: 永远不要使用字符串拼接(如 "WHERE id=" + id),必须使用 bind 以防止 SQL 注入。

执行方法

all()
  • 场景: 查询多行,获取列表、搜索结果。
  • 返回: Promise 解析为 { results: Array, meta: Object }results 是包含每一行对象的数组。
first(column?)
  • 场景: 查询单行,根据 ID 查详情、查总数 (COUNT)。
  • 用法:
  1. first(): 返回第一行对象(无结果返回 null)。
  2. first("column_name"): 直接返回第一行该列的(如直接拿到 count 数值)。
run()
  • 场景: 写入/修改INSERT, UPDATE, DELETE
  • 返回: { success: Boolean, meta: Object }注意:它不返回数据行
  • Meta 信息: meta.changes (受影响行数), meta.last_row_id (自增 ID)。

高级方法

batch([stmt1, stmt2, ...])
  • 作用: 批量执行。将多个 PreparedStatement 打包成一个请求。
  • 优势: 只有一次网络往返(Round-trip),性能远高于 await 循环;提供原子性(伪事务),保证语句按顺序执行或报错。
exec(sql_string)
  • 作用: 执行包含多条 SQL 的纯字符串
  • 限制: 不支持参数绑定 (bind)
  • 场景: 仅用于数据库初始化(Migration)、批量建表。严禁用于处理用户输入

API 速查表

方法属于对象用途返回值特征对应 SQL
prepare(sql)env.DB编译 SQL返回 PreparedStatement-
bind(...)Statement填入参数返回 PreparedStatement-
all()Statement查列表{ results: [] }SELECT
first()Statement查单行Object 或 nullSELECT ... LIMIT 1
first('col')Statement查单值Value (int/string)SELECT count(*)
run()Statement写操作{ success, meta }INSERT/UPDATE
batch([])env.DB批量打包[{result1}, {result2}]多条语句
exec(str)env.DB跑脚本PreparedStatement多条语句 (无参)

KV 键值存储

什么是 KV

Cloudflare Workers KV 是一个全球分布式键值存储系统。可以把它想象成一个存储在云端的、持久化的 Map 或 JSON 对象。

核心特性

  • 键值对结构: 只能通过 Key 存取 Value,不支持 SQL。
  • 全球低延迟: 写入后数据会同步到全球 300+ 数据中心。用户读取时,直接从最近的节点获取,实现毫秒级读取。
  • 最终一致性 (Eventual Consistency): 写入新值后,通常需要 60 秒内才能同步到全球。这意味着刚写入的数据可能不会立即被读取到(写慢读快)。

适用场景与对比

KV 非常适合**“读多写少”**的场景,如缓存、配置管理、Session 存储。

存储产品对比:

特性KV (Workers KV)D1 (SQL Database)R2 (Object Storage)
数据模型键值对 (Key -> Value)关系型表 (Table, Row)文件/对象 (File)
查询方式只能根据 Key 查SQL 语句 (SELECT *)只能根据文件名查
主要用途极速读取的小数据结构化的业务数据大文件存储
一致性最终一致 (写慢读快)强一致性 (支持事务)强一致性
典型场景缓存、配置、Session用户表、订单、元数据图片、视频、备份

KV 常用接口

假设你在 wrangler.toml 中绑定了名为 MY_KV 的命名空间,通过 env.MY_KV 调用以下方法。

put(key, value, options)

  • 作用写入
  • Key: 字符串(最大 512 字节)。
  • Value: String, ReadableStream, ArrayBuffer (最大 25MB)。
  • Options:
  • expiration: 绝对过期时间(Unix 时间戳)。
  • expirationTtl: 相对过期时间(秒),最小 60 秒。
  • metadata: 杀手级功能,允许附带额外的 JSON 对象,无需读取 Value 即可获取。

get(key, options)

  • 作用读取

  • 核心参数 type 自动转换数据格式。

  • "text" (默认): 返回字符串。

  • "json": 自动解析为对象。

  • "stream": 返回 ReadableStream,适合直接透传给 Response。

  • 缓存参数 cacheTtl 控制边缘节点缓存时长,减少回源查询。

其他常用方法

  • getWithMetadata(key): 同时返回 { value, metadata }
  • delete(key): 删除数据。即使 Key 不存在也会返回成功。
  • list(options): 列出 Key。支持 prefix (前缀筛选), limit (数量), cursor (分页)。

R2 对象存储 (Object Storage)

什么是 R2

Cloudflare R2 是对标 Amazon S3 的对象存储服务,主要用于存储图片、视频、PDF 等非结构化大型数据。

核心卖点:零出口流量费

这是 R2 最大的优势。

  • 传统云 (AWS/阿里云): 存储要钱,下载/读取(流量)也要钱。流量费往往比存储费贵得多。
  • Cloudflare R2: 存储要钱(价格亲民),但取用(下载)完全免费。无论产生了多少 TB 流量,都不收流量费。

对比表:R2 vs D1 vs KV

特性R2 (Object Storage)D1 (SQL Database)KV (Key-Value)
比喻仓库/文件柜Excel 表格便签纸/字典
存什么大文件 (图片, 视频, ZIP)业务数据 (用户, 订单)配置, 缓存, Token
大小限制单个文件可达 5 TB整个库 10 GB单个值最大 25 MB
费用重点存得多就贵,流量免费存得多就贵读得多就贵

R2 接口详解

R2 提供两种 API:S3 兼容 API (用于现有工具) 和 Workers 原生 API (用于开发)。在 Workers/Pages 中,我们主要使用原生 API (基于 env.BUCKET 绑定)。

put(key, value, options)

  • 作用上传
  • Options:
  • httpMetadata: 设置 HTTP 头(如 contentType)。这很重要,决定了浏览器是预览还是下载文件。
  • customMetadata: 自定义的 Key-Value 数据。

get(key)

  • 作用下载
  • 返回值: R2ObjectBody 对象(如果找到)或 null
  • 核心属性:
  • .body: ReadableStream。文件内容流,可以直接传给 new Response(obj.body) 实现零内存开销下载。
  • .httpMetadata: 之前存入的 Content-Type 等信息。

head(key)

  • 作用: 仅查元数据,检查文件是否存在,获取大小或类型,但不下载内容(Body 为空),节省资源。

前端直传

Workers 原生 API 目前不支持生成预签名 URL。如果需要让前端直接上传文件到 R2(不消耗 Worker 资源),你需要引入 S3 SDK (aws4fetch@aws-sdk/client-s3) 来生成 Presigned URL。

开发工具

本章将详细介绍 Cloudflare 官方命令行工具 Wrangler。它是连接开发者本地环境与 Cloudflare 全球边缘网络的桥梁,集成了开发、调试、数据库管理和一键部署等核心功能。

Wrangler 简介

什么是 Wrangler

Wrangler 是 Cloudflare Workers 和 Pages 的官方命令行接口 (CLI)。

如果把 Cloudflare Workers 比作一辆赛车,那么 Wrangler 就是这辆车的方向盘 + 仪表盘 + 维修工具箱。它是你开发、测试、配置和部署 Cloudflare 应用的核心入口。

简单来说:你写的代码想要跑到 Cloudflare 的全球网络上,必须经过 Wrangler

核心作用

Wrangler 主要解决了开发过程中的三个痛点:

  1. 本地开发 (Local Development):
  • 它在你的电脑上模拟 Cloudflare 的边缘环境。
  • 原理: 启动一个基于 workerd 运行时(Cloudflare 开发的轻量级服务器),其行为与线上的真实节点几乎完全一致。
  • 优势: 你不需要每次修改一行代码就部署到云端去测试。
  1. 资源绑定 (Bindings Management):
  • 它负责将你的代码与 D1 数据库KV 存储R2 存储桶连接起来。
  • 通过配置文件,它告诉 Worker:“env.DB 这个变量对应的是哪个数据库”。
  1. 一键部署 (Deployment):
  • 将你的代码、配置和环境变量打包,瞬间分发到 Cloudflare 全球 300+ 个城市的数据中心。

工作原理

当你运行 npx wrangler dev 时,后台发生了以下过程:

  1. Wrangler 读取 wrangler.toml 配置文件。
  2. 启动一个基于 Miniflare 的本地模拟器。
  3. src/index.js 编译并运行在这个服务器中。
  4. D1 模拟: 如果配置了 D1,它会在本地 .wrangler 文件夹下生成一个 SQLite 文件来模拟 D1 数据库,确保本地操作不会污染线上真实数据。

核心命令速查

Wrangler 功能丰富,但在日常开发中,掌握以下 20% 的核心命令即可解决 90% 的问题。

提示: 建议总是使用 npx wrangler <命令> 来运行,确保使用的是项目依赖中安装的版本,而不是全局版本。

基础与鉴权

  • npx wrangler login

  • 作用: 弹窗打开浏览器,授权 Wrangler 访问你的 Cloudflare 账号。

  • 场景: 第一次在新电脑上开发,或者 Token 过期时。

  • npx wrangler whoami

  • 作用: 查看当前登录的用户信息,以及关联的 Account ID。

开发与调试

这是开发过程中使用频率最高的命令。

  • npx wrangler dev (针对纯 Workers 项目)

  • npx wrangler pages dev <目录> (针对 Pages/全栈项目)

    • 作用: 启动本地开发服务器,监听文件变化。

    • 核心参数:

      • --local (默认):在本地模拟所有服务(D1, KV, R2)。读写的是本地临时文件,不影响线上数据

      • --remote:在本地运行代码,但连接云端的真实资源。如果你想在本地调试时读写线上的 D1 数据库,必须加上这个参数。

      • --compatibility-date=2024-01-01:指定兼容性日期。

      • 快捷键: 运行中按 l 键,可以在 Local 和 Remote 模式间动态切换。

数据库操作

Wrangler 是操作 D1 数据库的主要入口。

  • npx wrangler d1 create <数据库名>

    • 作用: 创建一个新的数据库。
  • npx wrangler d1 list

    • 作用: 列出所有数据库及其 ID。
  • npx wrangler d1 execute <数据库名> --file=./schema.sql

    • 作用: 执行 SQL 脚本文件。常用于数据库初始化(建表)。
    • 关键参数:
      • --local (默认):在本地开发环境的临时数据库执行。
      • --remote必须显式加上,才会对云端真实的数据库执行。
  • npx wrangler d1 execute <数据库名> --command="SELECT * FROM users"

    • 作用: 执行单条 SQL 语句。常用于快速查数据、Debug。

监控与日志

  • npx wrangler tail
    • 作用: 实时监听云端 Worker 的日志流。
    • 场景: 类似于 Linux 的 tail -f。当你部署上去后发现报错(如 500 Error),用这个命令可以看到 console.log 的输出和异常堆栈。
    • 技巧: 可以配合 grep 过滤日志,例如 npx wrangler tail | grep "Error"

部署与发布

  • npx wrangler deploy (Workers)
  • npx wrangler pages deploy <构建目录> (Pages)
    • 作用: 将代码和静态资源发布到公网。
    • 示例: npx wrangler pages deploy dist --project-name my-115-tool

环境变量与敏感信息管理

在开发过程中,如何安全地管理 API Key、Token 或 Cookie 等敏感信息至关重要。

线上环境 (Secrets)

严禁将密码或 Cookie 直接写在代码里提交到 GitHub。对于线上环境,应使用 Cloudflare 的 Secret 存储。

  • npx wrangler secret put <KEY_NAME>

    • 作用: 上传一个加密的环境变量到 Cloudflare。
    • 交互: 运行后,终端会提示输入具体的值(输入过程不可见)。
    • 示例: 设置 COOKIE_115
  • npx wrangler secret list

    • 作用: 列出已设置的密钥名称(出于安全考虑,不会显示具体的值)。

本地开发环境 (.dev.vars)

Wrangler 在本地运行时(wrangler pages dev),不会读取 Cloudflare 后台设置的 Secret,而是读取项目根目录下的 .dev.vars 文件。

操作步骤:

  1. 在项目根目录创建文件 .dev.vars
  2. 填入变量,格式为 KEY=VALUE

文件示例 (.dev.vars):

text
COOKIE_115=UID=12345;CID=abcde;SEID=...

注意: 确保 .dev.vars 文件在 .gitignore 中,防止意外提交到版本控制系统。

常用工作流总结

针对全栈项目(如 115 网盘工具),推荐的日常工作流命令如下:

  1. 日常开发:npx wrangler pages dev .
  2. 修改数据库结构 (本地测试):npx wrangler d1 execute my-db --local --file=./schema.sql
  3. 修改数据库结构 (应用到线上):npx wrangler d1 execute my-db --remote --file=./schema.sql
  4. 发布上线:npm run build && npx wrangler pages deploy dist

实战:115 网盘本地化工具

本章将整合前几章学习的 Pages (前端托管)、Functions (后端逻辑) 和 Wrangler (本地开发) 知识,构建一个完整的全栈应用——“115 网盘本地化管理工具”。

这个项目的核心痛点是:115 网盘的 API 有严格的 Cookie 校验和防盗链机制,前端无法直接在浏览器中调用(会报跨域 CORS 错误)。我们需要利用 Cloudflare Pages Functions 作为“中间人”来转发请求。

115 网盘实战架构

核心逻辑

该项目的架构设计如下:

  1. 前端 (Vue 3): 负责界面交互(如展示文件列表、重命名按钮、删除按钮)。
  2. 后端 (Pages Functions): 运行在 Cloudflare 边缘,负责中转请求。它会读取环境变量中的 Cookie,伪造请求头欺骗 115 服务器,并将结果返回给前端。
  3. 本地环境: 使用 Wrangler 模拟 Cloudflare 生产环境,代理 Vite 服务器。

项目初始化与结构

首先创建一个标准的 Vue 项目,然后在根目录下建立 Cloudflare Pages 特有的目录结构。

text
my-115-project/
├── .dev.vars          # 本地敏感变量 (存放 Cookie)
├── package.json       # 项目依赖与脚本
├── wrangler.toml      # 资源绑定配置
├── src/               # Vue 前端代码
│   └── App.vue
└── functions/         # 后端 API 代码 (约定路由)
    └── api/
        ├── 115.js     # -> 映射为 /api/115 接口
        └── img-proxy.js # -> 映射为 /api/img-proxy 接口

接口与鉴权 (通用中转)

我们需要编写一个通用的 API 接口,用于接收前端传来的目标 URL,并附带上 Cookie 转发给 115。

后端代码实现

请在 functions/api/115.js 中写入以下代码:

javascript
export async function onRequest(context) {
  // 1. 从环境变量中获取 Cookie
  // 在本地,它读取 .dev.vars;在线上,它读取 Cloudflare 后台配置的 Secrets
  const COOKIE = context.env.COOKIE_115

  if (!COOKIE) {
    return new Response(JSON.stringify({ state: false, error: '未配置 Cookie' }), {
      headers: { 'Content-Type': 'application/json' }
    })
  }

  // 2. 获取前端传来的参数 (Target URL)
  const url = new URL(context.request.url)
  const targetUrl = url.searchParams.get('url') // 例如 ?url=https://webapi.115.com/...

  if (!targetUrl) {
    return new Response('Missing url param', { status: 400 })
  }

  // 3. 发起请求给 115 (Server-to-Server)
  // 注意:这里伪造了 User-Agent 和 Cookie,绕过 115 的校验
  const resp = await fetch(targetUrl, {
    headers: {
      'User-Agent':
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
      Cookie: COOKIE
    }
  })

  // 4. 把 115 的返回结果直接透传给前端
  const data = await resp.json()
  return new Response(JSON.stringify(data), {
    headers: { 'Content-Type': 'application/json' }
  })
}

API 深度解析

  • onRequest(context): 这是 Pages Functions 的标准入口函数。

  • context.env: 这是一个包含所有环境变量的对象。

    • 本地开发时:它加载 .dev.vars 文件中的内容。
    • 线上部署时:它加载 Cloudflare Dashboard 中设置的 Environment Variables (Secrets)。
  • context.request: 一个标准的 Web API Request 对象,包含了前端发来的所有信息(URL、Method、Headers)。

严禁将 Cookie 硬编码在代码中提交到 GitHub。

  • 线上环境: 使用 Wrangler 命令上传加密存储:
bash
npx wrangler secret put COOKIE_115
# 终端会提示你输入具体的值,输入过程不可见
  • 本地环境: 详见 5.4 节。

图片代理服务 (防盗链处理)

115 的图片服务器有防盗链检查,如果请求头中的 Referer 不是 115.com,图片将无法加载(显示 403 Forbidden)。我们需要一个代理来“清洗”请求头。

后端代码实现

请在 functions/api/img-proxy.js 中写入以下代码:

javascript
export async function onRequest(context) {
  const COOKIE = context.env.COOKIE_115
  const url = new URL(context.request.url)
  const targetUrl = url.searchParams.get('url')

  if (!targetUrl) return new Response('Missing URL', { status: 400 })

  // 发起请求,核心在于伪造 Referer
  const resp = await fetch(targetUrl, {
    headers: {
      Cookie: COOKIE,
      Referer: 'https://115.com/' // 关键:骗过防盗链检查
    }
  })

  // 直接返回图片流 (Stream),实现零内存开销
  // 不要使用 await resp.blob(),那会消耗大量内存
  return new Response(resp.body, {
    headers: {
      // 转发原始图片的 Content-Type (如 image/jpeg)
      'Content-Type': resp.headers.get('Content-Type') || 'image/jpeg'
    }
  })
}

前端调用示例

在 Vue 组件中,你不能直接写 <img src="https://115.com/img/..." />。 你需要写:

html
<img src="/api/img-proxy?url=https://115.com/img/..." />

这样请求会先发给你的 Worker,Worker 加上 Referer: https://115.com/ 后再去请求 115,从而成功拿到图片。


本地全栈开发环境

为了在本地同时运行 Vue 前端和 Functions 后端,并让它们能够通信,我们需要配置 Wrangler 代理。

配置本地环境变量

Wrangler 在本地运行时不会去读取线上的 Secrets。你必须在项目根目录创建一个 .dev.vars 文件。

文件内容 (.dev.vars):

text
COOKIE_115=UID=12345;CID=abcde;SEID=...

注意: 等号周围不要有空格。此文件包含敏感信息,请务必加入 .gitignore

修改启动脚本

普通的 npm run dev 只能启动 Vue,无法运行 functions/ 目录下的后端代码。我们需要修改 package.jsonscripts 字段。

修改前:

json
"scripts": {
  "dev": "vite",
  "build": "vite build"
}

修改后:

json
"scripts": {
  "dev": "vite",
  "build": "vite build",
  "pages:dev": "wrangler pages dev -- proxy 5173"
}

运行与调试

在终端运行以下命令启动开发环境:

bash
npm run pages:dev

运行原理解析:

  1. 启动 Wrangler: 命令会启动 Wrangler 的本地服务器(通常在 http://localhost:8788)。

  2. 启动 Vite: Wrangler 会自动运行 npm run dev(启动 Vite 服务器,端口 5173)。

  3. 请求代理 (Proxy):

    • 当你访问 http://localhost:8788/api/115 时 -> Wrangler 拦截请求 -> 执行 functions/api/115.js -> 返回结果。

    • 当你访问 http://localhost:8788/assets/logo.png 时 -> Wrangler 发现这不是 API -> 将请求转发给 Vite (端口 5173) -> 返回静态资源。

    重要提示: 在浏览器中开发时,请务必访问 http://localhost:8788,而不是 Vite 的 5173 端口,否则你的 API 请求会失败(404 或跨域)。